/*
 * Valentine Gladstein
 * SOLAR ID 108731583
 * Homework #6
 * CSE214
 * Recitation 03-Phil Ammirato
 * Grading TA: Yanjie Li
 */

import java.io.*;
import java.util.*;

public class SpamDriver {

    //The SpamDriver class provides a console-driven menu system for manipulating a SpamFilter object and using it to scan emails

    private static SpamFilter filter;
    private static final String FILENAME = "SpamFilter.obj";
    private static final float SPAM_RATIO = (float)0.05;

    private ArrayList<EmailInfo> emails;


/**
 * Tries to load a saved SpamFilter pobject to be used by this SPamDriver. 
 * If no saved file is found, a new one is created.
 *
 */
    private static void loadFilter() {
	try {
	    FileInputStream fis = new FileInputStream(FILENAME);
	    ObjectInputStream ois = new ObjectInputStream(fis);

	    filter = (SpamFilter)ois.readObject();
	    ois.close();
	}
	catch (Exception e) {            //If file was not found, create a new SpamFilter object
	    filter = new SpamFilter();
	    System.out.println("No saved filter was found. A new(empty) filter has been created.");
	}
    }


/**
 * Saves the current SpamFilter object.
 *
 */
    private static void saveFilter() {
	try {
	    FileOutputStream fos = new FileOutputStream(FILENAME);
	    ObjectOutputStream oos = new ObjectOutputStream(fos);

	    oos.writeObject((Object)filter);
	    oos.close();
	}
	catch (Exception e) {            //If file was not written successfully
	    System.out.println("Unscpecified error occurred while saving filter.");
	}
    }


/**
 * Parses the input String as per the specifications of a single line of an EMialInfo.txt file, creating an EmailInfo object form the line.
 * @param line:  the string to be parsed
 * @return An EmialInfo object created based on the @param
 * @throws IOExcpetion: An IOExcpetion is thrown if an error occurs during any IO operation
 */
    private EmailInfo parseLine(String line) throws IOException{
	String[] lineParts = line.split("\t");
	EmailInfo newEmail = new EmailInfo();

	newEmail.setTo(lineParts[0]);
	newEmail.setFrom(lineParts[1]);	
	newEmail.setDate(lineParts[2]);
	newEmail.setSubject(lineParts[3]);
	newEmail.setFileLocation(lineParts[4]);

	//throw exception if ioerror
	try {
	    BufferedReader reader = new BufferedReader(new FileReader(lineParts[4]));
	    String message = reader.readLine();
	    String temp = reader.readLine();
	    while (temp != null) {
		message += temp;
		temp = reader.readLine();
	    }
	    reader.close();
	newEmail.setMessage(message);
	return newEmail;
	}
	catch (Exception E) {
	    throw new IOException();                  //if an expetion occurrs while retrieving email body, the excpetion is re-thrown to be handled by the caller
	}
    }

/**
 * Calls parseLine on each line of @param. This method then calls the current SPamFilter's checkEmail(String) method on each EmailInfo in emails and sets the spamPribability field for each.
 * @param file:  The EmailInfo.txt file containing email information to be checked.
 */
    private void checkEmailFile(String file) {
	BufferedReader reader;
	try {
	    reader = new BufferedReader(new FileReader(file));
	    String temp = reader.readLine();
	    while (temp != null) {
		emails.add(parseLine(temp));
		temp = reader.readLine();
	    }
	    reader.close();	

	    for (int i = 0; i < emails.size(); i++) {
		emails.get(i).setSpamProbability(filter.checkEmail(emails.get(i).getMessage()));
	    }
	}
	catch(Exception E){
	    System.out.println("Error occurred while loading one or more email files.");
	}
    }


/**
 * Formats and displays all information for each item in emails, 
 * including whether each message is considered spam.
 * 
 */
    public void displayResults() {

	if (emails.size() == 0)
	    return;
	
	System.out.println("\n                                   SCAN RESULTS");
	System.out.println("\n----------------------------------------------------------------------------------------");
	System.out.print("  ");
	System.out.printf("%-18s %-18s %-18s %-18s %-18s","To","From","Date","Subject","Filename");
	System.out.println("\n-------------------------------------------------------------------------------------
---");
	System.out.println();
	System.out.println("Inbox - spam marked with a *\n");

	String temp = "  ";
	for (int i = 0; i < emails.size(); i++) {
	    EmailInfo email = emails.get(i);
	    if (email.getSpamProbability() >= SPAM_RATIO)
		temp = " *";
	    System.out.print(temp);
	    System.out.printf("%-18s %-18s %-18s %-18s %-18s",email.getTo(),email.getFrom(),email.getDate(),email.getSubject(),email.getFileLocation());
	    System.out.println();
	}
	System.out.println("----------------------------------------------------------------------------------------");
    }


/**
 * Prompts user to enter a word to be added to the badWords SpamFilter. 
 * The word is added, and saveFilter() is used to serialize badWords.
 * 
 */
    private void insertWord() {
	String input;
	System.out.println("Word to insert: ");
	input = getInput();
	filter.insert(input);
	saveFilter();
	System.out.println(input + " was added to the spam filter's list.");
    }

/**
 * Prompts user to enter a word to be removed from the badWords SpamFilter. 
 * The word is removed, and saveFilter() is used to serialize badWords.
 * 
 */
    private void removeWord() {
	String input;
	System.out.println("Word to remove: ");
	input = getInput();
	try {
	    filter.remove(input);
	    System.out.println(input + " was removed from the spam filter's list.");
	    saveFilter();
	}
	catch(EntryNotFoundException E) {
	    System.out.println(input + " was not found in the spam filter's list.");
	}
    }

/**
 * Prompts user to enter a word to be searched for in the badWords SpamFilter. 
 * Prints out the search's result to sandard output.
 * 
 */
    private void searchWord() {
	String input;
	System.out.println("Word to search for: ");
	input = getInput();

	if (filter.isBadWord(input))
	    System.out.println(input + " IS in the spam filter's list of bad words.");
	else
	    System.out.println(input + " IS NOT in the spam filte's list.");
    }

    /**
     * Displays the main menu in the standard output and 
     * gets the user's input selection.
     * @return The user's entry, converted to lowercase.
     */
    public static String displayMenu(){

	System.out.println("\n\n-------------------------------");
	System.out.println("Main Menu");
	System.out.println("-------------------------------");
	System.out.println("C: Check emails");
	System.out.println("I: Insert word");
	System.out.println("R: Remove word");
	System.out.println("S: Search for word");
	System.out.println("Q: Quit the pogram");
	System.out.println("-------------------------------\n");
	System.out.println("");
	System.out.print("Please make a selection: ");

	return getInput();

    }

    /**
     * A helper method used internally to read user input from the standard input
     * @return a string containing the user's input
     */
    public static String getInput() {
	String s = "";
	InputStreamReader isr = new InputStreamReader(System.in);
	BufferedReader br = new BufferedReader(isr);
	try {
	    s = br.readLine();

	} catch (IOException e) {}
	return s.toLowerCase();
    }

    /**
     * Provides a way for the user to quit the program gracefully
     *
     */
    private void quit() {
        System.out.println("\nTerminating program normally....\n\n");
        System.exit(0);
    }

    /**
     * Provides a menu-driven system for manipulating the 
     * SpamDriver class. This method loops back to displaying 
     * the menu after every action the user takes.
     *
     */ 
    public static void main(String[] args) {	
	SpamDriver driver = new SpamDriver();
	driver.loadFilter();

	while (true){
	    String str = displayMenu();
	    if (str.equals("c")) {
		driver.emails = new ArrayList<EmailInfo>();
		System.out.println("Enter name of file containing email info: ");
		str =  getInput(); 
		driver.checkEmailFile(str);
		driver.displayResults();
	    }
	    else if (str.equals("i"))
		driver.insertWord();
	    else if (str.equals("r"))
		driver.removeWord();
	    else if (str.equals("s"))
		driver.searchWord();
	    else if (str.equals("q"))
		driver.quit();
	    else System.out.println("Input not recognized. Please make a valid selection:");
	}
	
    }
}

 

